#include "its.h"
#include <QDebug>

namespace IAlib
{

ITS::ITS()
{
}

ITS::ITS(const ITS &its)
{
    QMapIterator<QString, DomainModel*> domain_it(its.getDomainModels());
    while (domain_it.hasNext())
    {
        domain_it.next();
        addDomainModel(*domain_it.value());
    }
    QMapIterator<QString, LearnerModel*> learner_it(its.getLearnerModels());
    while (learner_it.hasNext())
    {
        learner_it.next();
        addLearnerModel(*learner_it.value());
    }
}

ITS::~ITS()
{
    QMapIterator<QString, DomainModel*> domain_it(m_domain_models);
    while (domain_it.hasNext())
    {
        domain_it.next();
        delete(m_domain_models[domain_it.key()]);
    }
    QMapIterator<QString, LearnerModel*> learner_it(m_learner_models);
    while (learner_it.hasNext())
    {
        learner_it.next();
        delete(m_learner_models[learner_it.key()]);
    }
}

void ITS::init()
{
	QMapIterator<QString, DomainModel*> domain_it(m_domain_models);
    while (domain_it.hasNext())
    {
        domain_it.next();
        delete(m_domain_models[domain_it.key()]);
    }
	m_domain_models.clear();
    QMapIterator<QString, LearnerModel*> learner_it(m_learner_models);
    while (learner_it.hasNext())
    {
        learner_it.next();
        delete(m_learner_models[learner_it.key()]);
    }
	m_learner_models.clear();
}
void ITS::addDomainModel(const DomainModel &domain_model)
{
    DomainModel  * newDomainModel = new DomainModel(domain_model);
    m_domain_models.insert(newDomainModel->getActorId(),newDomainModel);
}

void ITS::removeDomainModel(const QString &role)
{
    if (m_domain_models.contains(role))
    {
        delete(m_domain_models[role]);
        m_domain_models.remove(role);
    }
}

void ITS::addLearnerModel(const LearnerModel &learner_model)
{
    LearnerModel * newLearnerModel = new LearnerModel(learner_model);
    m_learner_models.insert(learner_model.getId(), newLearnerModel);
}

DomainModel* ITS::getDomainModel(const QString &role)
{
    if (m_domain_models.contains(role))
    {
        return m_domain_models[role];
    }
    else
    {
        return NULL;
    }
}

LearnerModel* ITS::getLearnerModel(const QString &id)
{
    if (m_learner_models.contains(id))
    {
        return m_learner_models[id];
    }
    else
    {
        return NULL;
    }
}

Evaluation* ITS::getEvaluation(const QString &id)
{
    if (m_evaluations.contains(id))
    {
        return m_evaluations[id];
    }
    else
    {
        return NULL;
    }
}

QMap<QString, DomainModel*> ITS::getDomainModels() const
{
    return m_domain_models;
}

QMap<QString, LearnerModel*> ITS::getLearnerModels() const
{
    return m_learner_models;
}

void ITS::on_its_action_emit(const ItsAction &action)
{
    if (m_learner_models.contains(action.getActorId()))
    {
        m_learner_models[action.getActorId()]->addAction(action);
        Q_EMIT its_action_added(action);
    }
}

void ITS::finalEvaluation(const QString id)
{
    /*if (m_learner_models.contains(id) && m_learner_models[id]->getPerformedMissions().size() > 0)
    {
        QList<QString>  missions = m_learner_models[id]->getPerformedMissions();
        QList<Mission*> sorted_missions;
        while (missions.size() > 1)
        {
            int index_min = 0;
            for (int i = 1; i < missions.size(); i++)
            {
                if (missions[i]->getImportance() < missions[index_min]->getImportance())
                {
                    index_min = i;
                }
            }
            sorted_missions.append(missions[index_min]);
            missions.removeAt(index_min);
        }
        sorted_missions.append(missions[0]);
        IAlib::Evaluation * eval  = new Evaluation();
        eval->setId(id);
        eval->setSortedMissions(sorted_missions);
        eval->exeEvaluation(m_learner_models[id]->getActions());
        if (m_evaluations.contains(id))
        {
            delete(m_evaluations[id]);
            m_evaluations.remove(id);
            m_evaluations.insert(id, eval);
        }
        else
        {
            m_evaluations.insert(id, eval);
        }
    }*/
}

QDomDocument ITS::toXML(const QString &file_name) const
{
    QDomDocument doc ("ITS");
    QDomElement root = doc.createElement("ITS1");
    doc.appendChild(root);
    QDomElement domainModels = doc.createElement( "domainModels" );
    QMapIterator<QString, DomainModel*> domain_it(m_domain_models);
    while (domain_it.hasNext())
    {
        domain_it.next();
        domainModels.appendChild(m_domain_models[domain_it.key()]->toXML(doc));
    }
    //doc.appendChild(domainModels);
    root.appendChild(domainModels);
    QDomElement learnerModels = doc.createElement( "learneModels" );
    QMapIterator<QString, LearnerModel*> learner_it(m_learner_models);
    while (learner_it.hasNext())
    {
        learner_it.next();
        learnerModels.appendChild(m_learner_models[learner_it.key()]->toXML(doc));
    }
    //doc.appendChild(learnerModels);
    root.appendChild(learnerModels);

    QFile  file(file_name);
    if( !file.open( QIODevice::WriteOnly ) )
    {
        // error
        return doc;
    }
    QTextStream ts( &file );
    ts.setCodec(QTextCodec::codecForName("UTF-8"));
    ts << doc.toString();
    file.close();
    return doc;
}

int ITS::fromXML(const QString &file_name)
{
    QMapIterator<QString, DomainModel*> domain_it(m_domain_models);
    while (domain_it.hasNext())
    {
        domain_it.next();
        delete(m_domain_models[domain_it.key()]);
    }
    m_domain_models.clear();
    QMapIterator<QString, LearnerModel*> learner_it(m_learner_models);
    while (learner_it.hasNext())
    {
        learner_it.next();
        delete(m_learner_models[learner_it.key()]);
    }
    m_learner_models.clear();

    //------------------------------------

    QDomDocument doc( "ITS" );
    QFile file( file_name );
    if( !file.open( QIODevice::ReadOnly ) )
      return -1;
    if( !doc.setContent( &file ) )
    {
      file.close();
      return -2;
    }
    file.close();
    QDomElement root = doc.documentElement();
    QDomNode n = root.firstChild();
    while( !n.isNull() )
    {
        QDomElement e = n.toElement();
        if( !e.isNull() )
        {
            if( e.tagName() == "domainModels" )
            {
                QDomNode domainNode = e.firstChild();
                while (!domainNode.isNull())
                {
                    DomainModel domain_model;
                    domain_model.fromXML(domainNode.toElement());
                    addDomainModel(domain_model);
                    domainNode = domainNode.nextSibling();
                }
            }
            else if (e.tagName() == "learneModels")
            {
                QDomNode learnerNode = e.firstChild();
                while (!learnerNode.isNull())
                {
                    LearnerModel learner_model;
                    learner_model.fromXML(learnerNode.toElement());
                    addLearnerModel(learner_model);
                    learnerNode = learnerNode.nextSibling();
                }
            }
        }
        n = n.nextSibling();
    }
    return 1;
}

QByteArray ITS::toByteArray() const
{
    QDomDocument doc = toXML("");
    QByteArray byte_array;
    QDataStream data(&byte_array, QIODevice::WriteOnly);
    data<<doc.toString();
    return byte_array;
}

int ITS::fromByteArray(QByteArray &byte_array)
{
    QDomDocument doc;
    QDataStream data(&byte_array, QIODevice::ReadOnly);
    QString xml;
    data>>xml;
    if (!doc.setContent(xml))
    {
        return -1;
    }
    QDomElement root = doc.documentElement();
    QDomNode n = root.firstChild();
    while( !n.isNull() )
    {
        QDomElement e = n.toElement();
        if( !e.isNull() )
        {
            if( e.tagName() == "domainModels" )
            {
                QDomNode domainNode = e.firstChild();
                while (!domainNode.isNull())
                {
                    DomainModel domain_model;
                    domain_model.fromXML(domainNode.toElement());
                    addDomainModel(domain_model);
                    domainNode = domainNode.nextSibling();
                }
            }
            else if (e.tagName() == "learneModels")
            {
                QDomNode learnerNode = e.firstChild();
                while (!learnerNode.isNull())
                {
                    LearnerModel learner_model;
                    learner_model.fromXML(learnerNode.toElement());
                    addLearnerModel(learner_model);
                    learnerNode = learnerNode.nextSibling();
                }
            }
        }
        n = n.nextSibling();
    }
    return 1;
}

ITS& ITS::operator =(const ITS& its)
{
    QMapIterator<QString, DomainModel*> _domain_it(m_domain_models);
    while (_domain_it.hasNext())
    {
        _domain_it.next();
        delete(m_domain_models[_domain_it.key()]);
    }
    m_domain_models.clear();
    QMapIterator<QString, LearnerModel*> _learner_it(m_learner_models);
    while (_learner_it.hasNext())
    {
        _learner_it.next();
        delete(m_learner_models[_learner_it.key()]);
    }
    m_learner_models.clear();
    QMapIterator<QString, DomainModel*> domain_it(its.getDomainModels());
    while (domain_it.hasNext())
    {
        domain_it.next();
        addDomainModel(*domain_it.value());
    }
    QMapIterator<QString, LearnerModel*> learner_it(its.getLearnerModels());
    while (learner_it.hasNext())
    {
        learner_it.next();
        addLearnerModel(*learner_it.value());
    }
    return *this;
}

}
